#pragma once

#include <MOE/Core/BasicTypes.h>
#include "TypeToken.hpp"

#include <memory>
#include <unordered_map>

namespace MOE
{
	namespace Core
	{
		class ClassMeta;
	}

	namespace System
	{
		class ClassLibrary;

		namespace NonIntrusive
		{
			// Manages a map of token -> ClassMeta and stores all registered ClassMeta in a ClassLibrary within.
			//
			// Has a singleton member, which is used by other global/static functions under NonIntrusive.
			class TokenClassMetaManager
			{
			public:
				static void InitializeSingleton();
				static void ReleaseSingleton();
				static bool SingletonInitialized();
				static TokenClassMetaManager* GetInstance();

			private:
				// This singleton has to be manually initialized/released by calling InitializeSingleton()/ReleaseSingleton().
				// This gives us better control of the singleton's lifetime.
				static TokenClassMetaManager* sInstance;

			public:
				TokenClassMetaManager();
				~TokenClassMetaManager();

				// Creates a class meta. This pointer is owned by mLibrary and should thus only be used to initialize the rest of the class meta structure.
				Core::ClassMeta* CreateClassMeta(tTokenType classType, tTokenType parentType, const Core::char8* className, Core::tSize elementSize);

				const Core::ClassMeta& GetClassMeta(tTokenType tokenValue) const;

				void DestroyClassMeta(tTokenType classType);

			private:
				// Immediately creates class meta for basic types as soon as the TokenClassMetaManager is created.
				void InitializeBaseTypes();

				// Helper class to create basic type class meta.
				template <class T>
				void CreateBasicTypeClassMeta(Core::BasicType basicTypeEnum, const Core::char8* basicTypeName);

				typedef std::unordered_map<tTokenType, Core::ClassMeta*> tClassMetaMap;

				tClassMetaMap mClassMetaMap;
				std::unique_ptr<ClassLibrary> mLibrary;
			};
		}
	}
}
